<?php
/**
 * Here is your custom functions.
 */

if (!function_exists('getTreeData')) {
    /**
     * 无限级递归查询下级数据并支持sort排序
     * @param $data //数据源
     * @param int $pid //父级ID
     * @param int $level
     * @return array
     */
    function getTreeData($data, int $pid = 0, int $level = 0): array
    {
        $tree = [];
        foreach ($data as $k => $v) {
            if ($v['pid'] == $pid) {
                $v['level'] = $level;
                $children = getTreeData($data, $v['id'], $level + 1);
                if ($children) {
                    // 对子级按sort字段排序
                    usort($children, function ($a, $b) {
                        return $a['sort'] <=> $b['sort'];
                    });
                    $v['children'] = $children;
                }
                $tree[] = $v;
            }
        }
        // 对当前层级按sort字段排序
        usort($tree, function ($a, $b) {
            return $a['sort'] <=> $b['sort'];
        });
        return $tree;
    }
}

if (!function_exists('url')) {
    function url($url = '', $params = [])
    {

        return !empty($params) ? $url . '?' . http_build_query($params) : $url;
    }
}

if (!function_exists('mkdir_folder')) {
    /**
     * 判断文件夹是否存在不存在则创建
     * @param $dir
     * @param int $mode
     * @return bool
     */
    function mkdir_folder($dir, int $mode = 0777): bool
    {
        if (is_dir($dir) || @mkdir($dir, $mode)) return TRUE;
        if (!mkdir_folder(dirname($dir), $mode)) return FALSE;
        return @mkdir($dir, $mode);
    }
}

if (!function_exists('set_log')) {
    /**
     * 自定义日志
     * @param $name
     * @param $content
     * @return void
     */
    function set_log($name, $content): void
    {
        $ary = explode("_", $name);
        if (count($ary) > 1) {
            $folder = $ary[0];
        } else {
            $folder = 'public';
        }

        $fileName = $name . '_' . date('Y-m-d_H') . '.txt';     //日志文件
        $catalogue = './public/log';                                          //日志公共目录
        mkdir_folder($catalogue);
        $filePath = $catalogue . '/' . $folder;                        //日志类别目录
        mkdir_folder($filePath);
        $fileUrl = $filePath . '/' . $fileName;                        //完整路径
        $Ts = fopen($fileUrl, "a+");
        fputs($Ts, "\r\n" . "执行日期：" . date('Y-m-d H:i:s', time()) . ' ' . "\n" . $content . "\n");
        fclose($Ts);
    }
}

if (!function_exists('token')) {
    /**
     * 生成 token 【新增加的】
     * @access public
     * @param string $name 令牌名称
     * @param string $type 加密函数
     * @return string
     */
    function token(string $name = '__token__', string $type = 'md5'): string
    {
        $type = is_callable($type) ? $type : 'md5';
        $token = call_user_func($type, microtime());
        request()->session()->set($name, $token);
        return $token;
    }
}

if (!function_exists('checkToken')) {
    /**
     * 检查请求令牌
     * @access public
     * @param string $token 令牌名称
     * @param array $data 表单数据
     * @return bool
     */
    function checkToken(string $token = '__token__', array $data = []): bool
    {
        $request = request();
        $session = $request->session();
        if (in_array($request->method(), ['GET', 'HEAD', 'OPTIONS'], true)) {
            return true;
        }
        if (!$session->has($token)) {
            // 令牌数据无效
            return false;
        }
        // Header验证
        if ($request->header('X-CSRF-TOKEN') && $session->get($token) === $request->header('X-CSRF-TOKEN')) {
            // 防止重复提交
            $session->delete($token); // 验证完成销毁session
            return true;
        }
        if (empty($data)) {
            $data = $request->post();
        }
        // 令牌验证
        if (isset($data[$token]) && $session->get($token) === $data[$token]) {
            // 防止重复提交
            $session->delete($token); // 验证完成销毁session
            return true;
        }
        // 开启TOKEN重置
        $session->delete($token);
        return false;
    }
}

if (!function_exists('get_package_version')) {
    /**
     * 获取某个composer包的版本
     * @param string $package
     * @return mixed|string
     */
    function get_package_version(string $package)
    {
        $installed_php = base_path('vendor/composer/installed.php');
        if (is_file($installed_php)) {
            $packages = include $installed_php;
        }
        return substr($packages['versions'][$package]['version'] ?? 'unknown  ', 0, -2);
    }
}

if (!function_exists('html_encode')) {
    /**
     * 过滤
     * 有效防止XSS攻击和SQL注入
     * @param $str
     * @return array|string|string[]|void
     */
    function html_encode($str)
    {
        if (empty($str)) return;
        $str = trim($str);
        $str = str_replace("&", "&amp;", $str);
        $str = str_replace(">", "&gt;", $str);
        $str = str_replace("<", "&lt;", $str);
        $str = str_replace(chr(32), "&nbsp;", $str);
        $str = str_replace(chr(34), "&quot;", $str);
        $str = str_replace(chr(39), "&#39;", $str);
        return $str;
    }
}

if (!function_exists('filterWords')) {
    /**
     * 正则表达式过滤
     * 过滤掉常见的恶意代码和SQL关键字
     * @param $str
     * @return string
     */
    function filterWords(&$str)
    {
        $farr = array(
            "/<(\\/?)(script|i?frame|style|html|body|title|link|meta|object|null|\\?|\\%)([^>]*?)>/isU",
            "/(<[^>]*)on[a-zA-Z]+\\s*=([^>]*>)/isU",
            "/select\\b|insert\\b|update\\b|delete\\b|drop\\b|;|\\\"|\\'|\\/\\*|\\*|\\.\\.\\/|\\.\\/|union|into|load_file|outfile|dump/is"
        );
        $str = preg_replace($farr, '', $str);
        $str = strip_tags($str);
        return $str;
    }
}